package org.kineticsproject.fusion;

import java.sql.Timestamp;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

//import org.kineticsproject.devices.parsers.UnitConverter;
//import org.kineticsproject.visualizations.XYSeriesExt;

import data.DataFactory;
import data.DataSample;
import data.Exercise;
import data.DataLog;
import data.DisplacementSample;
import data.FusedDataSample;

public class HeterogeneousTypeDataFuser extends Fuser {

	@Override
	public boolean process(Exercise exercise) {
		
		DataLog      dl;
		
		// clear the fused data set in case it already contains data
		
		DataLog fdl = DataFactory.eINSTANCE.createDataLog(); 
		exercise.setFusedDataLog(fdl);
		//exercise.getFusedDataLog().getDataSamples().clear();
		
		// prepare fuseddatalog
		int samplePeriod = 60;
		Date startTimestamp = exercise.getEarliestTimestamp();
		System.out.println("Start Time: "+startTimestamp.toString()+"\n");
		Date endTimestamp = exercise.getLatestTimestamp();
		System.out.println("End Time: "+endTimestamp.toString()+"\n");
		
		prep(startTimestamp,endTimestamp, samplePeriod ,exercise.getFusedDataLog());
		
		startTimestamp = exercise.getFusedDataLog().getStartTime();
		System.out.println("Start Time: "+startTimestamp.toString()+"\n");
		endTimestamp = exercise.getFusedDataLog().getEndTime();
		System.out.println("End Time: "+endTimestamp.toString()+"\n");
		
		//DataLog fdl = DataFactory.eINSTANCE.createDataLog(); //new FusedDataLog(startTimestamp, endTimestamp, samplePeriod);
		
		Iterator<DataLog> it = exercise.getDatalogs().iterator();
		
		while(it.hasNext())
		{
			process(exercise.getFusedDataLog(),it.next());
		}
		
		calculateExerciseStatistics(exercise);
		return(true);
	}

	
	private void calculateExerciseStatistics(Exercise exercise)
	{
		calculateHeartRateStatistics(exercise);
	}
	
	private void calculateHeartRateStatistics(Exercise exercise)
	{
		
		
		int hrMax = 220 - 28;
		int min = 32767;
		int max = 0;
		double mean;
		int otherCount = 0;
		int aerobicCount = 0;
		int anaerobicCount = 0;
		int recoveryCount = 0;
		int vo2maxCount = 0;
		int totalCount = 0;
		long total = 0;
		
		FusedDataSample fsample;
		
		Iterator<DataSample> it = exercise.getFusedDataLog().getDataSamples().iterator();
		
		while (it.hasNext())
		{
			
			fsample = (FusedDataSample)it.next();
			
			if (fsample.getHeartratesample() != null)
			{
				int hr = fsample.getHeartratesample().getHeartRate();
	
				total = total + hr;
				
				if (hr > max)
					max = hr;
				
				if (hr < min)
					min = hr;
				
	
				if (hr >= (0.9 * hrMax))
				{
					++vo2maxCount;
				} else if (hr >= (0.8 * hrMax))
				{
					++anaerobicCount;
				} else if (hr >= (0.7 * hrMax))
				{
					++aerobicCount;
				} else if (hr >= 0.6 * hrMax)
				{
					++recoveryCount;
				} else
				{
					++otherCount;
				}
	
			}
		}
		totalCount = otherCount + recoveryCount + aerobicCount + anaerobicCount
		+ vo2maxCount;
		exercise.setAerobicPercentage(100 * (double) aerobicCount
				/ (double) totalCount);
		exercise.setAnaerobicPercentage(100 * (double) anaerobicCount
				/ (double) totalCount);
		exercise.setOtherPercentage(100 * (double) otherCount
				/ (double) totalCount);
		exercise.setRecoveryPercentage(100 * (double) recoveryCount
				/ (double) totalCount);
		exercise.setVo2maxPercentage(100 * (double) vo2maxCount
				/ (double) totalCount);
		
		
		exercise.setHeartrateAverage((double) total / (double) totalCount);
		exercise.setHeartrateMaximum(max);
		exercise.setHeartrateMinimum(min);
		
		System.out.println("Calculated Heartrate Data\n");
	}
	
	
	private void prep(Date startTimestamp, Date endTimestamp, int samplePeriod /*seconds*/, DataLog fusedDataLog)
	{
		Date 				currentTimestamp = new Date(startTimestamp.getTime());
		FusedDataSample		currentFusedDataSample;	
				
		//fusedDataLog.setStartTime(startTimestamp);	
		
		while(currentTimestamp.getTime() < endTimestamp.getTime())
		{
			System.out.println("Current Timestamp: "+currentTimestamp.toString()+"\n");
			
			currentFusedDataSample = DataFactory.eINSTANCE.createFusedDataSample();
			//currentFusedDataSample.setDataLogId(this.getDataLogId());
			currentFusedDataSample.setTimestamp(new Date (currentTimestamp.getTime()));
			fusedDataLog.getDataSamples().add(currentFusedDataSample);
			
			currentTimestamp.setTime(currentTimestamp.getTime()+(1000*samplePeriod)); // increment one second, (milliseconds)

		}
	}
	
	
	private boolean process(DataLog fdl, DataLog dl) {
		
		//FusedDataSample 	fds = (FusedDataSample)fdl.head();
		DisplacementSample  lastDisplacementSample 	= null;
		DisplacementSample  curDisplacementSample 	= null;
		
		//Class c = dl.head().getClass();
		//System.out.println("Class: "+c.getName());
		
		Iterator<DataSample> itfdl = fdl.getDataSamples().iterator();
		//Iterator<DataSample> itdl  = dl.getDataSamples().iterator();
		
		while(itfdl.hasNext() && !dl.getDataSamples().isEmpty())
		{
			try
			{
				FusedDataSample fds = (FusedDataSample) itfdl.next();
				
				Class classPositionSample 		= Class.forName("data.PositionSample");
				Class classHeartRateSample 		= Class.forName("data.HeartRateSample");
				Class classDisplacementSample 	= Class.forName("data.DisplacementSample");
	
				if (classPositionSample.isInstance(dl.getDataSamples().get(0)))
				{
					fds.setPositionsample(((data.PositionSample)dl.findNearestSample(fds)).clone());	
					//fds = (FusedDataSample)itfdl.next();	
				}
				else if (classHeartRateSample.isInstance(dl.getDataSamples().get(0)))
				{
					fds.setHeartratesample(((data.HeartRateSample)dl.findNearestSample(fds)).clone());	
					//fds = (FusedDataSample)fdl.next();	
				}
				else if (classDisplacementSample.isInstance(dl.getDataSamples().get(0)))
				{
					
				
					curDisplacementSample = (data.DisplacementSample)dl.findNearestSample(fds);
					//fds.setDisplacementsample(curDisplacementSample);
					
					if ((lastDisplacementSample == null) ) // if first iteration
					{
						fds.setDisplacementsample(curDisplacementSample.clone());
					}
				/*	else if (curDisplacementSample == null)
					{
						curDisplacementSample = lastDisplacementSample;
						fds.setDisplacementsample(curDisplacementSample.clone());
					}*/
					// if the displacment sample has already been referenced by a fused sample clone the sample and negate the displacement
					else if ((curDisplacementSample.equalsExceptDisplacement(lastDisplacementSample)) && (lastDisplacementSample.getDisplacement() != 0))
					{
						fds.setDisplacementsample(curDisplacementSample.clone());
						fds.getDisplacementsample().setDisplacement(0);
						
					}
					// use the dummy DisplacementSample w/o any displacement value
					else if ((curDisplacementSample.equalsExceptDisplacement(lastDisplacementSample)) && (lastDisplacementSample.getDisplacement() == 0))
					{
						fds.setDisplacementsample(lastDisplacementSample.clone());
						
					}
					else // the displacement sample is not referenced by another fused data sample, use it
					{
						fds.setDisplacementsample(curDisplacementSample.clone());
					}
					
					lastDisplacementSample = fds.getDisplacementsample();
					
					//fds = fdl.getDataSamples()	
					
				}
				
			}
			catch (ClassNotFoundException e)
			{
				System.err.print(e);
			}
			

		}
		
		return(true);
		
	}
	
	

}
